package com.df.dht.dht;

import com.df.dht.util.NodeIdUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.*;

@Slf4j
@Component
public class Spider implements ApplicationListener<ContextClosedEvent> {

    @Autowired
    private DHTServerHandler dhtServerHandler;
    private EventLoopGroup group;
    private static ChannelFuture serverChannelFuture;

    /**
     * 本机 DHT 节点 ID （根据 IP 生成）
     */
    public static final byte[] SELF_NODE_ID = NodeIdUtil.randSelfNodeId();


    /**
     * 启动节点列表
     */
    public static final List<InetSocketAddress> BOOTSTRAP_NODES = new ArrayList<>(Arrays.asList(
            new InetSocketAddress("router.bittorrent.com", 6881),
            new InetSocketAddress("dht.transmissionbt.com", 6881),
            new InetSocketAddress("router.utorrent.com", 6881),
            new InetSocketAddress("dht.aelitis.com", 6881)));


    @PostConstruct
    public void start() {
        try {
            group = new NioEventLoopGroup();
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    .handler(new ChannelInitializer<DatagramChannel>() {
                        @Override
                        protected void initChannel(DatagramChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("handler", dhtServerHandler);
                        }

                    });
            Map<ChannelOption<?>, Object> udpChannelOptions = udpChannelOptions();
            Set<ChannelOption<?>> keySet = udpChannelOptions.keySet();
            for (@SuppressWarnings("rawtypes")
            ChannelOption option : keySet) {
                b.option(option, udpChannelOptions.get(option));
            }

            log.info("Starting dht server at " + 9999);
            serverChannelFuture = b.bind(9999).sync();
            serverChannelFuture.channel().closeFuture();
        }catch (Exception e) {
            e.printStackTrace();
        }


    }

    public Map<ChannelOption<?>, Object> udpChannelOptions() {
        Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
        options.put(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        options.put(ChannelOption.SO_BROADCAST, true);
        options.put(ChannelOption.SO_RCVBUF, 268435456);
        options.put(ChannelOption.SO_SNDBUF, 65536);
        return options;
    }
    @Override
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        if(contextClosedEvent.getApplicationContext().getParent() == null) {
            group.shutdownGracefully();
        }
    }

    /**
     * 发送 KRPC 协议数据报文
     *
     * @param packet
     */
    public static void sendKRPC(DatagramPacket packet) {
        if(serverChannelFuture != null) {
            serverChannelFuture.channel().writeAndFlush(packet);
        }
    }
}
